package com.yc.services;

import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.fasterxml.jackson.core.JsonProcessingException; // ⬅️ **新增: Jackson ObjectMapper 相关的导入**
import com.fasterxml.jackson.databind.ObjectMapper; // ⬅️ **新增: Jackson ObjectMapper 相关的导入**
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class PsychologyAnalysisService {
    private static final Logger logger = LoggerFactory.getLogger(PsychologyAnalysisService.class);
    
    // Redis键前缀
    private static final String REDIS_KEY_PREFIX = "chat:Psychlogy:";
    // 数据在Redis中的过期时间（天）
    private static final long EXPIRE_DAYS = 30;

    @Value("${dashscope.api.key}")
    private String apiKey;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String QWEN_VL_MODEL = "qwen-vl-plus";
    private final ObjectMapper objectMapper = new ObjectMapper(); // ⬅️ **新增: Jackson ObjectMapper 实例**

    /**
     * 分析图片心理内容（流式输出）
     * @param imageUrl 图片URL
     * @param userId 用户ID
     * @return 心理分析结果的流式片段 (Flux<String>，每个 String 是一个 JSON 片段)
     */
    public Flux<String> analyzeImageStream(String imageUrl, String userId) {
        return Flux.create(fluxSink -> {
            try {
                MultiModalConversation conversation = new MultiModalConversation();

                // 构建系统消息
                List<Map<String, Object>> systemContentParts = new ArrayList<>();
                Map<String, Object> systemTextPart = new HashMap<>();
                systemTextPart.put("text", "你是一位专业的心理咨询师，请分析这张图片中反映的心理状态和情绪");
                systemTextPart.put("type", "text");
                systemContentParts.add(systemTextPart);

                MultiModalMessage systemMsg = MultiModalMessage.builder()
                        .role(Role.SYSTEM.getValue())
                        .content(systemContentParts)
                        .build();

                // 构建用户消息 - 包含文本和图片
                List<Map<String, Object>> userContentParts = new ArrayList<>();
                Map<String, Object> userTextPart = new HashMap<>();
                userTextPart.put("text", "请从心理学角度分析这张图片。");
                userTextPart.put("type", "text");
                userContentParts.add(userTextPart);

                Map<String, Object> userImagePart = new HashMap<>();
                userImagePart.put("image", imageUrl);
                userImagePart.put("type", "image");
                userContentParts.add(userImagePart);

                MultiModalMessage userMessage = MultiModalMessage.builder()
                        .role(Role.USER.getValue())
                        .content(userContentParts)
                        .build();

                // 创建参数
                MultiModalConversationParam param = MultiModalConversationParam.builder()
                        .model(QWEN_VL_MODEL)
                        .messages(Arrays.asList(systemMsg, userMessage))
                        .apiKey(apiKey)
                        .build();

                // 用于存储完整的分析结果
                StringBuilder fullAnalysisResult = new StringBuilder();

                // 流式调用 DashScope API
                conversation.streamCall(param, new com.alibaba.dashscope.common.ResultCallback<MultiModalConversationResult>() {
                    private String lastFullContent = ""; // 用于存储上一次的完整内容，以便计算增量

                    @Override
                    public void onEvent(MultiModalConversationResult result) {
                        if (result.getOutput() != null &&
                                result.getOutput().getChoices() != null &&
                                !result.getOutput().getChoices().isEmpty()) {

                            MultiModalMessage message = result.getOutput().getChoices().get(0).getMessage();
                            List<Map<String, Object>> contents = message.getContent();

                            if (contents == null || contents.isEmpty()) {
                                logger.warn("模型返回了空内容列表。请求ID: {}, 结束原因: {}", result.getRequestId(), result.getOutput().getChoices().get(0).getFinishReason());
                                return;
                            }

                            StringBuilder currentFullContentBuilder = new StringBuilder();
                            for (Map<String, Object> item : contents) {
                                if (("text".equals(item.get("type")) || item.get("type") == null)
                                        && item.get("text") instanceof String) {
                                    currentFullContentBuilder.append(item.get("text"));
                                }
                            }
                            String currentFullContent = currentFullContentBuilder.toString();

                            // 关键：计算增量并将其封装为 JSON 对象推送
                            if (currentFullContent.length() > lastFullContent.length()) {
                                String newChunk = currentFullContent.substring(lastFullContent.length());
                                if (!newChunk.isEmpty()) {
                                    Map<String, String> data = new HashMap<>();
                                    data.put("text", newChunk); // 将增量文本放入 "text" 字段
                                    try {
                                        // ⬅️ **将增量文本封装到 JSON 对象并发送**
                                        fluxSink.next(objectMapper.writeValueAsString(data));
                                        logger.debug("已推送增量 JSON 片段: {}", objectMapper.writeValueAsString(data));
                                    } catch (JsonProcessingException e) {
                                        logger.error("将增量数据转换为 JSON 失败", e);
                                        fluxSink.error(e); // 如果 JSON 转换失败，发送错误到流
                                    }
                                }
                            }
                            lastFullContent = currentFullContent; // 更新 lastFullContent
                            
                            // 更新完整的分析结果
                            fullAnalysisResult.setLength(0);
                            fullAnalysisResult.append(currentFullContent);

                        } else {
                            logger.warn("DashScope API 返回的输出或选择为空。原始结果: {}", result);
                            // 遇到异常情况，通常我们会等待 onComplete 或 onError，但如果确定这是错误，也可以在这里发射错误。
                        }
                    }

                    @Override
                    public void onComplete() {
                        // 分析完成后，将完整结果存储到Redis
                        saveAnalysisToRedis(userId, imageUrl, fullAnalysisResult.toString());
                        
                        fluxSink.complete(); // ⬅️ **流式完成，通知前端**
                        logger.info("心理分析流式完成，用户ID: {}", userId);
                    }

                    @Override
                    public void onError(Exception e) {
                        fluxSink.error(e); // ⬅️ **流式出错，通知前端**
                        logger.error("心理分析流式过程中出错，用户ID: {}", userId, e);
                    }
                });

            } catch (NoApiKeyException | InputRequiredException | UploadFileException e) {
                logger.error("初始化心理分析流失败，用户ID: {}", userId, e);
                fluxSink.error(new RuntimeException("心理分析服务初始化失败: " + e.getMessage())); // ⬅️ **发送错误到流**
            }
        }, FluxSink.OverflowStrategy.BUFFER); // 使用 BUFFER 策略，防止数据丢失
    }
    
    /**
     * 将分析结果保存到Redis
     * @param userId 用户ID
     * @param imageUrl 图片URL
     * @param analysisText 分析文本结果
     */
    private void saveAnalysisToRedis(String userId, String imageUrl, String analysisText) {
        try {
            String redisKey = REDIS_KEY_PREFIX + userId;
            
            // 构建存储的数据结构
            Map<String, Object> analysisData = new HashMap<>();
            analysisData.put("imageUrl", imageUrl);
            analysisData.put("analysisText", analysisText);
            analysisData.put("createTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            
            // 将数据序列化为JSON字符串
            String jsonData = objectMapper.writeValueAsString(analysisData);
            
            // 存储到Redis，设置过期时间
            redisTemplate.opsForValue().set(redisKey, jsonData, EXPIRE_DAYS, TimeUnit.DAYS);
            
            logger.info("心理分析结果已保存到Redis，用户ID: {}, Redis键: {}", userId, redisKey);
            
        } catch (JsonProcessingException e) {
            logger.error("序列化分析数据失败，用户ID: {}", userId, e);
        } catch (Exception e) {
            logger.error("保存分析结果到Redis失败，用户ID: {}", userId, e);
        }
    }

    /**
     * 获取用户的心理分析历史记录
     * @param userId 用户ID
     * @return 心理分析数据的JSON字符串，如果不存在则返回null
     */
    /**
     * 获取用户的心理分析历史记录
     * @param userId 用户ID
     * @return 心理分析数据的JSON数组字符串，如果不存在则返回null
     */
    public String getAnalysisHistory(String userId) {
        try {
            // 构建Redis key模式：用户ID_*
            String pattern = REDIS_KEY_PREFIX + userId + "_*";

            // 获取所有匹配的keys
            Set<String> keys = redisTemplate.keys(pattern);

            if (keys == null || keys.isEmpty()) {
                logger.info("用户心理分析历史记录不存在，用户ID: {}", userId);
                return null;
            }

            // 获取所有匹配的值
            List<Object> values = redisTemplate.opsForValue().multiGet(keys);

            if (values == null || values.isEmpty()) {
                logger.info("用户心理分析历史记录为空，用户ID: {}", userId);
                return null;
            }

            // 构建JSON数组
            List<Map<String, Object>> historyList = new ArrayList<>();

            for (int i = 0; i < keys.size(); i++) {
                String key = keys.toArray(new String[0])[i];
                Object value = values.get(i);

                if (value != null) {
                    try {
                        // 解析JSON字符串
                        ObjectMapper objectMapper = new ObjectMapper();
                        Map<String, Object> analysisData = objectMapper.readValue(value.toString(), Map.class);

                        // 从key中提取时间戳
                        String[] keyParts = key.split("_");
                        if (keyParts.length >= 3) {
                            String timestamp = keyParts[keyParts.length - 1]; // 获取最后一部分作为时间戳
                            analysisData.put("timestamp", timestamp);
                            analysisData.put("id", key); // 添加唯一标识
                        }

                        historyList.add(analysisData);
                    } catch (Exception e) {
                        logger.warn("解析历史记录失败，key: {}", key, e);
                    }
                }
            }

            if (historyList.isEmpty()) {
                logger.info("没有有效的心理分析历史记录，用户ID: {}", userId);
                return null;
            }

            // 按时间戳降序排序（最新的在前面）
            historyList.sort((a, b) -> {
                try {
                    String timestampA = (String) a.get("timestamp");
                    String timestampB = (String) b.get("timestamp");
                    return Long.compare(Long.parseLong(timestampB), Long.parseLong(timestampA));
                } catch (Exception e) {
                    return 0;
                }
            });

            // 转换为JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();
            String result = objectMapper.writeValueAsString(historyList);

            logger.info("成功获取用户心理分析历史记录，用户ID: {}, 记录数量: {}", userId, historyList.size());
            return result;

        } catch (Exception e) {
            logger.error("获取用户心理分析历史记录失败，用户ID: {}", userId, e);
            return null;
        }
    }
}